<!DOCTYPE HTML>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="./resources/geometry-interfaces-test-helpers.js"></script>
<script>

test(() => {
  var matrix = new DOMMatrixReadOnly();
  assert_identity_2d_matrix(matrix);
}, "DOMMatrixReadOnly constructor");

test(() => {
  var matrix2d = new DOMMatrixReadOnly([1, 2, 3, 3.1, 2, 1]);
  assert_2d_matrix_equals(matrix2d, [1, 2, 3, 3.1, 2, 1]);
}, "DOMMatrixReadOnly constructor - 2D matrix");

test(() => {
  var matrix3d = new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
  assert_3d_matrix_equals(matrix3d, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
}, "DOMMatrixReadOnly constructor - 3D matrix");

test(() => {
  var float32Array = new Float32Array([1, 2, 3, 4, 5, 6]);
  var matrix2d = DOMMatrixReadOnly.fromFloat32Array(float32Array);
  assert_2d_matrix_equals(matrix2d, [1, 2, 3, 4, 5, 6]);
}, "DOMMatrixReadOnly fromFloat32Array - 2D matrix");

test(() => {
  // 3.1  is not representable as a 32-bit float
  var float64Array = new Float64Array([1, 2, 3, 3.1, 4, 5]);
  var matrix2d = DOMMatrixReadOnly.fromFloat64Array(float64Array);
  assert_2d_matrix_equals(matrix2d, [1, 2, 3, 3.1, 4, 5]);
}, "DOMMatrixReadOnly fromFloat64Array - 2D matrix");

test(() => {
  var float32Array = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
  var matrix3d = DOMMatrixReadOnly.fromFloat32Array(float32Array);
  assert_3d_matrix_equals(matrix3d, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
}, "DOMMatrixReadOnly fromFloat32Array - 3D matrix");

test(() => {
  // 10.1 and 16.6 are not representable as a 32-bit float
  var float64Array = new Float64Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
  var matrix3d = DOMMatrixReadOnly.fromFloat64Array(float64Array);
  assert_3d_matrix_equals(matrix3d, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
}, "DOMMatrixReadOnly fromFloat64Array - 3D matrix");

test(() => {
  var matrix = new DOMMatrixReadOnly("");
  assert_identity_2d_matrix(matrix);
}, "DOMMatrixReadOnly(transformList) - emptyString");

test(() => {
  var matrix = new DOMMatrixReadOnly("matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0) translate(44px, 55px) skewX(30deg)");
  var expectedMatrix = new DOMMatrixReadOnly();
  expectedMatrix = expectedMatrix.multiply(new DOMMatrixReadOnly([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]))
  expectedMatrix = expectedMatrix.translate(44, 55)
  expectedMatrix = expectedMatrix.skewX(30);
  assert_matrix_almost_equals(matrix, expectedMatrix);
}, "DOMMatrixReadOnly(transformList) - transformList");

test(() => {
  var matrix2d = new DOMMatrixReadOnly([1, 2, 3, 3.1, 2, 1.1]);
  assert_true(matrix2d.is2D);
  assert_equals(matrix2d.toString(), "matrix(1, 2, 3, 3.1, 2, 1.1)");
}, "DOMMatrixReadOnly toString() - 2D matrix");

test(() => {
  var matrix3d = new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
  assert_false(matrix3d.is2D);

  assert_equals(matrix3d.toString(), "matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6)");
}, "DOMMatrixReadOnly toString() - 3D matrix");

[NaN, Infinity, -Infinity].forEach(num => {
  test(() => {
    for (let i = 0; i < 6; ++i) {
      let seq = [1, 0, 0, 1, 0, 0];
      seq[i] = num;
      var matrix2d = new DOMMatrixReadOnly(seq, 6);
      assert_true(matrix2d.is2D);
      assert_throws_dom("InvalidStateError", () => { matrix2d.toString() });
    }
  }, `DOMMatrixReadOnly toString() - 2D matrix with ${num}`);

  test(() => {
    for (let i = 0; i < 12; ++i) {
      let seq = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
      seq[i] = num;
      var matrix3d = new DOMMatrixReadOnly(seq, 12);
      assert_false(matrix3d.is2D);
      assert_throws_dom("InvalidStateError", () => { matrix3d.toString() });
    }
  }, `DOMMatrixReadOnly toString() - 3D matrix with ${num}`);
});

test(() => {  var identity_matrix = DOMMatrixReadOnly.fromMatrix();
  assert_true(identity_matrix.is2D);
  assert_object_equals(identity_matrix.toJSON(),
    { a : 1, b : 0, c : 0, d : 1, e : 0, f : 0,
      is2D : true, isIdentity : true,
      m11 : 1, m12 : 0, m13 : 0, m14 : 0,
      m21 : 0, m22 : 1, m23 : 0, m24 : 0,
      m31 : 0, m32 : 0, m33 : 1, m34 : 0,
      m41 : 0, m42 : 0, m43 : 0, m44 : 1});
}, "DOMMatrixReadOnly toJSON() - identity matrix");

test(() => {
  var matrix2d = new DOMMatrixReadOnly([1, 2, 3, 3.1, 2, 1]);
  assert_true(matrix2d.is2D);
  assert_object_equals(matrix2d.toJSON(),
    { a : 1, b : 2, c : 3, d : 3.1, e : 2, f : 1,
      is2D : true, isIdentity : false,
      m11 : 1, m12 : 2, m13 : 0, m14 : 0,
      m21 : 3, m22 : 3.1, m23 : 0, m24 : 0,
      m31 : 0, m32 : 0, m33 : 1, m34 : 0,
      m41 : 2, m42 : 1, m43 : 0, m44 : 1});
}, "DOMMatrixReadOnly toJSON() - 2D matrix");

test(() => {
  var matrix3d = new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
  assert_false(matrix3d.is2D);
  assert_object_equals(matrix3d.toJSON(),
    { a : 1, b : 2, c : 5, d : 6, e : 13, f : 14,
      is2D : false, isIdentity : false,
      m11 : 1, m12 : 2, m13 : 3, m14 : 4,
      m21 : 5, m22 : 6, m23 : 7, m24 : 8,
      m31 : 9, m32 : 10.1, m33 : 11, m34 : 12,
      m41 : 13, m42 : 14, m43 : 15, m44 : 16.6});
}, "DOMMatrixReadOnly toJSON() - 3D matrix");

test(() => {
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly(1, 2, 3, 4, 5, 6); },
    "DOMMatrixReadOnly(transformList) can't parse unknown keyword - DOMMatrixReadOnly(1, 2, 3, 4, 5, 6) is same with DOMMatrixReadOnly('1')");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("myString"); },
    "DOMMatrixReadOnly(transformList) can't parse unknown keyword");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("initial");},
    "CSS-wide keywords are disallowed");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("notExistFunction()"); },
    "can't parse not exist function");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateY(50%)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(1.2em)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(10ex)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(10ch)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(10rem)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(10vw)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(10vh)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(10vmin)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(10vmax)"); },
    "using relative units should throw a SyntaxError");
  assert_throws_dom("SyntaxError", () => { new DOMMatrixReadOnly("translateX(calc(10px + 1em))"); },
    "using relative units should throw a SyntaxError");
  assert_throws_js(TypeError, () => { new DOMMatrixReadOnly([1, 2, 3]); },
    "DOMMatrixReadOnly constructor only accepts 1 number sequence with 6 or 16 elements");
}, "DOMMatrixReadOnly constructor - invalid arguments");

test(() => {
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array([1, 2, 3, 4, 5])); },
    "fromFloat32Array function only accepts 1 Float32Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array([1, 2, 3, 4, 5])); },
    "fromFloat64Array function only accepts 1 Float64Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array([1, 2, 3, 4, 5, 6 ,7])); },
    "fromFloat32Array function only accepts 1 Float32Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array([1, 2, 3, 4, 5, 6 ,7])); },
    "fromFloat64Array function only accepts 1 Float64Array with 6 or 16 elements");
}, "DOMMatrixReadOnly fromFloat*Array - invalid array size of nearby 6");

test(() => {
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array([1, 2, 3, 4, 5, 6 ,7, 8, 9, 10, 11, 12, 13, 14, 15])); },
    "fromFloat32Array function only accepts 1 Float32Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array([1, 2, 3, 4, 5, 6 ,7, 8, 9, 10, 11, 12, 13, 14, 15])); },
    "fromFloat64Array function only accepts 1 Float64Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array([1, 2, 3, 4, 5, 6 ,7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])); },
    "fromFloat32Array function only accepts 1 Float32Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array([1, 2, 3, 4, 5, 6 ,7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])); },
    "fromFloat64Array function only accepts 1 Float64Array with 6 or 16 elements");
}, "DOMMatrixReadOnly fromFloat*Array - invalid array size of nearby 16");

test(() => {
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array([])); },
    "fromFloat32Array function only accepts 1 Float32Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array([])); },
    "fromFloat64Array function only accepts 1 Float64Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array([1])); },
    "fromFloat32Array function only accepts 1 Float32Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array([1])); },
    "fromFloat64Array function only accepts 1 Float64Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array(65536)); },
    "fromFloat32Array function only accepts 1 Float32Array with 6 or 16 elements");
  assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array(65536)); },
    "fromFloat64Array function only accepts 1 Float64Array with 6 or 16 elements");
}, "DOMMatrixReadOnly fromFloat*Array - invalid array size");

if (window.SharedArrayBuffer) {
  test(() => {
    assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat32Array(new Float32Array(new SharedArrayBuffer(24))); },
      "");
    assert_throws_js(TypeError, () => { DOMMatrixReadOnly.fromFloat64Array(new Float64Array(new SharedArrayBuffer(32))); },
      "");
  }, "DOMMatrixReadOnly fromFloat*Array - can't use SharedArrayBuffer view");
}

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix();
  assert_identity_2d_matrix(matrix);
}, "DOMMatrixReadOnly.fromMatrix() with no parameter");

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix(null);
  assert_identity_2d_matrix(matrix);
}, "DOMMatrixReadOnly.fromMatrix() with null");

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix(undefined);
  assert_identity_2d_matrix(matrix);
}, "DOMMatrixReadOnly.fromMatrix() with undefined");

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix({});
  assert_identity_2d_matrix(matrix);
}, "DOMMatrixReadOnly.fromMatrix() with empty object");

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix({a: 1, b: 2, c: 3, d: 4, e: 5, f: 6});
  assert_2d_matrix_equals(matrix, [1, 2, 3, 4, 5, 6]);
}, "DOMMatrixReadOnly.fromMatrix({a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}) should create a 2D DOMMatrixReadOnly");

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix({m11: 1, m22: 2, m33: 3, m44: 4, m23: 5, m43: 6});
  assert_3d_matrix_equals(matrix, [1, 0, 0, 0, 0, 2, 5, 0, 0, 0, 3, 0, 0, 0, 6, 4]);
}, "DOMMatrixReadOnly.fromMatrix({m11: 1, m22: 2, m33: 3, m44: 4, m23: 5, m43: 6}) should create a 3D DOMMatrixReadOnly");

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix({a: 7, c: 9});
  assert_2d_matrix_equals(matrix, [7, 0, 9, 1, 0, 0]);
}, "If 2d related properties don't be set, should set to fallback");

test(() => {
  var matrix = DOMMatrixReadOnly.fromMatrix({
    m11: NaN, m12: NaN, m13: NaN, m14: NaN,
    m21: NaN, m22: NaN, m23: NaN, m24: NaN,
    m31: NaN, m32: NaN, m33: NaN, m34: NaN,
    m41: NaN, m42: NaN, m43: NaN, m44: NaN,
    is2D: false
  });
  assert_3d_matrix_equals(matrix, [NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN]);
}, "DOMMatrixReadOnly.fromMatrix(): NaN test");

test(() => {
  assert_throws_js(TypeError, () => {
    DOMMatrixReadOnly.fromMatrix({a: 1, b: 2, m33: 3, m44: 4, is2D: true});
  }, "The 'is2D' property is set to true but the input matrix is 3d matrix");
  assert_throws_js(TypeError, () => {
    DOMMatrixReadOnly.fromMatrix({a: 1, b: 2, m11: 3});
  }, "The 'a' property should equal the 'm11' property");
}, "DOMMatrixReadOnly.fromMatrix(): Exception test");

</script>
